#!/usr/bin/python3

import os,subprocess
import dbus
from advertisement import Advertisement
from service import Application, Service, Characteristic, Descriptor
from gpiozero import PingServer, CPUTemperature, LoadAverage, DiskUsage

GATT_CHRC_IFACE = "org.bluez.GattCharacteristic1"
NOTIFY_TIMEOUT = 5000

SERVICE_UUID = '00000001-710e-4a5b-8d75-3e5b444bc3cf'
POROTOCOL_VERSION = 1

COMMAND_REBOOT = 0x01
COMMAND_START_IHOMESERVER = 0x10
COMMAND_STOP_IHOMESERVER = 0x11

REBOOT_SCRIPT = '/home/pi/ihome/sh/reboot.sh'
IHOME_SERVER = 'ihomesvr'
START_IHOMESVR_SCRIPT = 'sudo systemctl start ' + IHOME_SERVER
STOP_IHOMESVR_SCRIPT = 'sudo systemctl stop ' + IHOME_SERVER

class IHomeAdvertisement(Advertisement):
    def __init__(self, index):
        Advertisement.__init__(self, index, "peripheral")
        self.add_local_name("ihome")
        self.include_tx_power = True

class IHomeService(Service):

    def __init__(self, index):
        Service.__init__(self, index, SERVICE_UUID, True)
        self.add_characteristic(StatusCharacteristic(self))
        self.add_characteristic(SSIDCharacteristic(self))
        self.add_characteristic(PasswordCharacteristic(self))
        self.add_characteristic(CommandCharacteristic(self))

    def set_ssid(self, data):
        self.wifi_ssid = data
    def get_ssid(self):
        return self.wifi_ssid
        
    def set_password(self, data):
        self.wifi_pasword = data
        self.setup_wifi()
    def get_password(self):
        return self.wifi_pasword

    def set_command(self,data):
        cmd = bytearray(data)[0]
        print(cmd)
        if(cmd == COMMAND_REBOOT):
            self.reboot()
        elif(cmd == COMMAND_START_IHOMESERVER):
            self.startIHomeServer()
        elif(cmd == COMMAND_STOP_IHOMESERVER):
            self.stopIHomeServer()
        else:
            print('unknown command id:' + cmd)

    def setup_wifi(self):
        wpa_supplicant_conf = "/boot/wpa_supplicant.conf"
        # write wifi config to file
        f = open('wifi.conf', 'w')
        f.write('country=CN\n')
        f.write('ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\n')
        f.write('update_config=1\n')
        f.write('\n')
        f.write('network={\n')
        f.write('    ssid="' + self.wifi_ssid + '"\n')
        f.write('    psk="' + self.wifi_pasword + '"\n')
        f.write('    priority=1\n')
        f.write('}\n')
        f.close()

        cmd = 'sudo mv -f wifi.conf ' + wpa_supplicant_conf
        cmd_result = ""
        cmd_result = os.system(cmd)
        print(cmd + " - " + str(cmd_result))

    def reboot(self):
        print('rebooting...')
        subprocess.Popen(REBOOT_SCRIPT)

    def startIHomeServer(self):
        print('starting iHome server...')
        os.system(START_IHOMESVR_SCRIPT)

    def stopIHomeServer(self):
        print('stoping iHome server...')
        os.system(STOP_IHOMESVR_SCRIPT)

class StatusCharacteristic(Characteristic):
    STATUS_CHARACTERISTIC_UUID = "00000002-710e-4a5b-8d75-3e5b444bc3cf"

    def __init__(self, service):
        self.notifying = False

        Characteristic.__init__(
                self, self.STATUS_CHARACTERISTIC_UUID,
                ["notify", "read"], service)
        self.add_descriptor(StatusDescriptor(self))

    def get_deviceinfo(self):
        value = []

        cputemp = int(CPUTemperature().temperature)
        cpula = int(LoadAverage().value*100)
        disk = int(DiskUsage().value*100)
        is_internet = bool(PingServer('baidu.com').value)
        output = os.popen('systemctl show ' + IHOME_SERVER + ' -p SubState | sed "s/SubState=//g"')
        svrstatus = output.read().strip('\n')
        svrstatus = 1 if svrstatus=='running' else 0
        value.append(dbus.Byte(POROTOCOL_VERSION))
        value.append(dbus.Byte(cputemp))
        value.append(dbus.Byte(cpula))
        value.append(dbus.Byte(disk))
        value.append(dbus.Byte(is_internet))
        value.append(dbus.Byte(svrstatus))

        return value

    def set_temperature_callback(self):
        if self.notifying:
            value = self.get_deviceinfo()
            self.PropertiesChanged(GATT_CHRC_IFACE, {"Value": value}, [])

        return self.notifying

    def StartNotify(self):
        if self.notifying:
            return

        self.notifying = True

        value = self.get_deviceinfo()
        self.PropertiesChanged(GATT_CHRC_IFACE, {"Value": value}, [])
        self.add_timeout(NOTIFY_TIMEOUT, self.set_temperature_callback)

    def StopNotify(self):
        self.notifying = False

    def ReadValue(self, options):
        value = self.get_deviceinfo()

        return value

class StatusDescriptor(Descriptor):
    STATUS_DESCRIPTOR_UUID = "2901"
    STATUS_DESCRIPTOR_VALUE = "Device Status"

    def __init__(self, characteristic):
        Descriptor.__init__(
                self, self.STATUS_DESCRIPTOR_UUID,
                ["read"],
                characteristic)

    def ReadValue(self, options):
        value = []
        desc = self.STATUS_DESCRIPTOR_VALUE

        for c in desc:
            value.append(dbus.Byte(c.encode()))

        return value

class SSIDCharacteristic(Characteristic):
    SSID_CHARACTERISTIC_UUID = "00000003-710e-4a5b-8d75-3e5b444bc3cf"

    def __init__(self, service):
        Characteristic.__init__(
                self, self.SSID_CHARACTERISTIC_UUID,
                ["read","write"], service)
        self.add_descriptor(SSIDDescriptor(self))

    def WriteValue(self, value, options):
        ssid = (bytearray(value)).decode()
        self.service.set_ssid(ssid)

    def ReadValue(self, options):
        ssid = self.service.get_ssid()
        value = []
        for c in ssid:
            value.append(dbus.Byte(c.encode()))

        return value

class SSIDDescriptor(Descriptor):
    SSID_DESCRIPTOR_UUID = "2901"
    SSID_DESCRIPTOR_VALUE = "SSID of Wifi"

    def __init__(self, characteristic):
        Descriptor.__init__(
                self, self.SSID_DESCRIPTOR_UUID,
                ["read"],
                characteristic)

    def ReadValue(self, options):
        value = []
        desc = self.SSID_DESCRIPTOR_VALUE

        for c in desc:
            value.append(dbus.Byte(c.encode()))

        return value

class PasswordCharacteristic(Characteristic):
    PASSWORD_CHARACTERISTIC_UUID = "00000004-710e-4a5b-8d75-3e5b444bc3cf"

    def __init__(self, service):
        Characteristic.__init__(
                self, self.PASSWORD_CHARACTERISTIC_UUID,
                ["read","write"], service)
        self.add_descriptor(PasswordDescriptor(self))

    def WriteValue(self, value, options):
        pwd = (bytearray(value)).decode()
        self.service.set_password(pwd)
                
    def ReadValue(self, options):
        pwd = self.service.get_password()
        print(pwd)

        value = []
        for c in pwd:
            value.append(dbus.Byte(c.encode()))
        print(value)

        return value

class PasswordDescriptor(Descriptor):
    PASSWORD_DESCRIPTOR_UUID = "2901"
    PASSWORD_DESCRIPTOR_VALUE = "Password of Wifi"

    def __init__(self, characteristic):
        Descriptor.__init__(
                self, self.PASSWORD_DESCRIPTOR_UUID,
                ["read"],
                characteristic)

    def ReadValue(self, options):
        value = []
        desc = self.PASSWORD_DESCRIPTOR_VALUE

        for c in desc:
            value.append(dbus.Byte(c.encode()))

        return value

class CommandCharacteristic(Characteristic):
    COMMAND_CHARACTERISTIC_UUID = "00000005-710e-4a5b-8d75-3e5b444bc3cf"

    def __init__(self, service):
        Characteristic.__init__(
                self, self.COMMAND_CHARACTERISTIC_UUID,
                ["write"], service)
        self.add_descriptor(CommandDescriptor(self))

    def WriteValue(self, value, options):
        self.service.set_command(value)

class CommandDescriptor(Descriptor):
    COMMAND_DESCRIPTOR_UUID = "2901"
    COMMAND_DESCRIPTOR_VALUE = "command"

    def __init__(self, characteristic):
        Descriptor.__init__(
                self, self.COMMAND_DESCRIPTOR_UUID,
                ["read"],
                characteristic)

    def ReadValue(self, options):
        value = []
        desc = self.COMMAND_DESCRIPTOR_VALUE

        for c in desc:
            value.append(dbus.Byte(c.encode()))

        return value

if __name__ == '__main__':

    app = Application()
    app.add_service(IHomeService(0))
    app.register()

    adv = IHomeAdvertisement(0)
    adv.add_service_uuid(SERVICE_UUID)
    adv.register()

    try:
        app.run()

    except KeyboardInterrupt:
        app.quit()
